package com.allm.ai.common.config;

import com.allm.ai.common.properties.AllmAiCommonProperties;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.validation.annotation.Validated;

/**
 * 配置验证器
 * 在应用启动时验证配置的一致性和完整性
 *
 * @author com.enplatform.assistant
 * @since 1.0.0
 */
@Slf4j
@Component
@Validated
@RequiredArgsConstructor
public class ConfigurationValidator {

    private final AllmAiCommonProperties properties;

    /**
     * 应用启动完成后验证配置
     */
    @EventListener
    public void validateConfiguration(ApplicationReadyEvent event) {
        log.info("开始验证EnPlatform Assistant配置...");
        
        try {
            validateAiConfiguration();
            validateVectorStoreConfiguration();

            // 只有在向量存储启用且provider为milvus时才验证Milvus配置
            if (properties.getVectorstore().getEnabled() && "milvus".equals(properties.getVectorstore().getProvider())) {
                validateMilvusConfiguration();
            }

            // 暂时跳过嵌入配置验证，用于Excel验证测试
            // validateEmbeddingsConfiguration();
            // validateExcelConfiguration();
            // validateApplicationConfiguration();

            log.info("✅ 配置验证通过");
        } catch (Exception e) {
            log.error("❌ 配置验证失败: {}", e.getMessage());
            throw new IllegalStateException("配置验证失败", e);
        }
    }

    /**
     * 验证AI配置
     */
    private void validateAiConfiguration() {
        AllmAiCommonProperties.Ai ai = properties.getAi();
        Assert.hasText(ai.getProvider(), "AI provider不能为空");
        
        String provider = ai.getProvider();
        switch (provider) {
            case "real":
            case "local":
                validateLocalAiConfiguration(ai.getLocal());
                break;
            case "openai":
                validateOpenAiConfiguration(ai.getOpenai());
                break;
            case "gitee":
                validateGiteeAiConfiguration(ai.getGitee());
                break;
            case "smart":
                validateLocalAiConfiguration(ai.getLocal());
                validateOpenAiConfiguration(ai.getOpenai());
                break;
            case "mock":
                // Mock模式不需要额外验证
                break;
            default:
                throw new IllegalArgumentException("不支持的AI provider: " + provider);
        }
        
        log.debug("AI配置验证通过: provider={}", provider);
    }

    /**
     * 验证本地AI配置
     */
    private void validateLocalAiConfiguration(AllmAiCommonProperties.Ai.Local local) {
        Assert.hasText(local.getBaseUrl(), "本地AI服务baseUrl不能为空");
        Assert.hasText(local.getModel(), "本地AI模型名称不能为空");
        Assert.isTrue(local.getTimeout() > 0, "本地AI超时时间必须大于0");
    }

    /**
     * 验证OpenAI配置
     */
    private void validateOpenAiConfiguration(AllmAiCommonProperties.Ai.OpenAi openai) {
        Assert.hasText(openai.getBaseUrl(), "OpenAI baseUrl不能为空");
        Assert.hasText(openai.getModel(), "OpenAI模型名称不能为空");
        Assert.isTrue(openai.getTimeout() > 0, "OpenAI超时时间必须大于0");
        
        // 如果不是mock模式，需要API Key
        if (!"mock".equals(properties.getAi().getProvider())) {
            Assert.hasText(openai.getApiKey(), "OpenAI API Key不能为空");
        }
    }

    /**
     * 验证Gitee AI配置
     */
    private void validateGiteeAiConfiguration(AllmAiCommonProperties.Ai.Gitee gitee) {
        Assert.hasText(gitee.getBaseUrl(), "Gitee AI baseUrl不能为空");
        Assert.hasText(gitee.getModel(), "Gitee AI模型名称不能为空");
        Assert.hasText(gitee.getApiKey(), "Gitee AI API Key不能为空");
        Assert.isTrue(gitee.getTimeout() > 0, "Gitee AI超时时间必须大于0");
    }

    /**
     * 验证向量存储配置
     */
    private void validateVectorStoreConfiguration() {
        AllmAiCommonProperties.Vectorstore vectorstore = properties.getVectorstore();
        Assert.hasText(vectorstore.getProvider(), "向量存储provider不能为空");
        Assert.notNull(vectorstore.getEnabled(), "向量存储enabled配置不能为空");

        log.debug("向量存储配置验证通过: provider={}, enabled={}", vectorstore.getProvider(), vectorstore.getEnabled());
    }

    /**
     * 验证Milvus配置
     */
    private void validateMilvusConfiguration() {
        AllmAiCommonProperties.Milvus milvus = properties.getMilvus();
        Assert.hasText(milvus.getHost(), "Milvus主机地址不能为空");
        Assert.isTrue(milvus.getPort() > 0 && milvus.getPort() <= 65535, "Milvus端口必须在1-65535范围内");
        Assert.hasText(milvus.getCollectionName(), "Milvus集合名称不能为空");
        Assert.isTrue(milvus.getDimension() > 0, "Milvus向量维度必须大于0");
        Assert.isTrue(milvus.getShardsNum() > 0, "Milvus分片数量必须大于0");
        
        // 验证连接配置
        AllmAiCommonProperties.Milvus.Connection connection = milvus.getConnection();
        Assert.isTrue(connection.getTimeout() > 0, "Milvus连接超时时间必须大于0");
        Assert.isTrue(connection.getPoolSize() > 0, "Milvus连接池大小必须大于0");
        
        log.debug("Milvus配置验证通过: {}:{}", milvus.getHost(), milvus.getPort());
    }

    /**
     * 验证嵌入配置
     */
    private void validateEmbeddingsConfiguration() {
        AllmAiCommonProperties.Embeddings embeddings = properties.getEmbeddings();
        AllmAiCommonProperties.Embeddings.Primary primary = embeddings.getPrimary();
        
        Assert.hasText(primary.getBaseUrl(), "嵌入服务baseUrl不能为空");
        Assert.hasText(primary.getModelName(), "嵌入模型名称不能为空");
        Assert.isTrue(primary.getDimension() > 0, "嵌入向量维度必须大于0");
        Assert.isTrue(primary.getTimeout() > 0, "嵌入服务超时时间必须大于0");
        Assert.isTrue(primary.getBatchSize() > 0, "嵌入批处理大小必须大于0");
        
        // 验证嵌入维度与Milvus维度一致
        if (properties.getVectorstore().getEnabled() && "milvus".equals(properties.getVectorstore().getProvider())) {
            Assert.isTrue(primary.getDimension().equals(properties.getMilvus().getDimension()),
                "嵌入向量维度(" + primary.getDimension() + ")必须与Milvus配置维度(" + properties.getMilvus().getDimension() + ")一致");
        }
        
        log.debug("嵌入配置验证通过: model={}, dimension={}", primary.getModelName(), primary.getDimension());
    }

    /**
     * 验证Excel配置
     */
    private void validateExcelConfiguration() {
        AllmAiCommonProperties.Excel excel = properties.getExcel();
        Assert.isTrue(excel.getMaxFileSize() > 0, "Excel最大文件大小必须大于0");
        Assert.isTrue(excel.getMaxRows() > 0, "Excel最大行数必须大于0");
        Assert.isTrue(excel.getBatchSize() > 0, "Excel批处理大小必须大于0");
        Assert.hasText(excel.getTempDir(), "Excel临时目录不能为空");
        Assert.notEmpty(excel.getSupportedFormats(), "Excel支持的文件格式不能为空");
        
        log.debug("Excel配置验证通过: maxFileSize={}, maxRows={}", excel.getMaxFileSize(), excel.getMaxRows());
    }

    /**
     * 验证应用配置
     */
    private void validateApplicationConfiguration() {
        AllmAiCommonProperties.Application app = properties.getApplication();
        Assert.hasText(app.getName(), "应用名称不能为空");
        Assert.hasText(app.getVersion(), "应用版本不能为空");
        Assert.hasText(app.getDescription(), "应用描述不能为空");
        
        // 验证文件配置
        AllmAiCommonProperties.Application.File file = app.getFile();
        Assert.hasText(file.getUploadPath(), "文件上传路径不能为空");
        Assert.hasText(file.getTempPath(), "临时文件路径不能为空");
        Assert.isTrue(file.getMaxSize() > 0, "文件最大大小必须大于0");
        Assert.notEmpty(file.getAllowedTypes(), "允许的文件类型不能为空");
        
        // 验证缓存配置
        AllmAiCommonProperties.Application.Cache cache = app.getCache();
        Assert.hasText(cache.getType(), "缓存类型不能为空");
        Assert.isTrue(cache.getTtl() > 0, "缓存TTL必须大于0");
        Assert.isTrue(cache.getMaxEntries() > 0, "缓存最大条目数必须大于0");
        
        log.debug("应用配置验证通过: name={}, version={}", app.getName(), app.getVersion());
    }
}
